package com.zhx.common.chat.service.strategy.mark;

import com.zhx.common.chat.dao.MessageMarkDao;
import com.zhx.common.chat.domain.dto.ChatMessageMarkDTO;
import com.zhx.common.chat.domain.entity.MessageMark;
import com.zhx.common.chat.domain.enums.MessageMarkActTypeEnum;
import com.zhx.common.chat.domain.enums.MessageMarkTypeEnum;
import com.zhx.common.common.domain.enums.YesOrNoEnum;
import com.zhx.common.common.event.MessageMarkEvent;
import com.zhx.common.common.exception.BusinessException;
import org.checkerframework.checker.units.qual.A;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Objects;
import java.util.Optional;

public abstract class AbstractMsgMarkStrategy {
    @Resource
    private MessageMarkDao messageMarkDao;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    protected abstract MessageMarkTypeEnum getTypeEnum();

    @PostConstruct
    private void init(){
        MsgMarkStrategyFactory.register(getTypeEnum().getType(), this);
    }

    /**
     *        --- 点踩
     * 标记---
     *        --- 点赞
     *
     *             --- 取消点踩
     * 取消标记---
     *             --- 取消点赞
     */

    @Transactional
    public void mark(Long uid,Long msgId){
        doMark(uid,msgId);
    }

    @Transactional
    public void unMark(Long uid,Long msgId){
        doUnMark(uid,msgId);
    }

    protected void doUnMark(Long uid, Long msgId) {
        exec(uid, msgId, MessageMarkActTypeEnum.UN_MARK);
    }

    protected void doMark(Long uid, Long msgId) {
        exec(uid,msgId, MessageMarkActTypeEnum.MARK);
    }


    /**
     * 执行消息标记操作，支持点赞或点踩以及确认或取消这些操作。
     *
     * @param uid 用户ID，执行标记操作的用户。
     * @param msgId 消息ID，被标记的消息。
     * @param actTypeEnum 操作类型枚举，定义是确认（点赞或点踩）还是取消操作。
     */
    protected void exec(Long uid, Long msgId, MessageMarkActTypeEnum actTypeEnum) {
        // 根据枚举获取标记类型（点赞或点踩）
        Integer markType = getTypeEnum().getType();
        // 根据传入的枚举获取操作类型（确认或取消）
        Integer actType = actTypeEnum.getType();
        // 尝试获取现有的消息标记
        MessageMark oldMark = messageMarkDao.get(uid,msgId,markType);
        if (Objects.isNull(oldMark) && actTypeEnum == MessageMarkActTypeEnum.UN_MARK) {
            // 如果是取消操作，但数据库中不存在对应的标记记录，则直接返回不做操作
            // 比如说我们有一个点赞请求，如果之前点了踩需要取消，但如果没点踩就不用继续执行了。
            return;
        }
        // 构建要插入或更新的消息标记对象
        MessageMark insertOrUpdate = MessageMark.builder()
                .id(Optional.ofNullable(oldMark).map(MessageMark::getId).orElse(null))
                .uid(uid)
                .msgId(msgId)
                .type(markType)
                .status(transformAct(actType))
                .build();

        // 尝试保存或更新消息标记记录
        boolean modify = messageMarkDao.saveOrUpdate(insertOrUpdate);
        if(modify){
            // 如果记录成功被修改，则发布一个消息标记事件
            ChatMessageMarkDTO messageMarkDTO = new ChatMessageMarkDTO(uid, msgId, markType, actType);
            applicationEventPublisher.publishEvent(new MessageMarkEvent(this, messageMarkDTO));
        }
    }

    private Integer transformAct(Integer actType) {
        if (actType == 1) {
            return YesOrNoEnum.NO.getStatus();
        } else if (actType == 2) {
            return YesOrNoEnum.YES.getStatus();
        }
        throw new BusinessException("动作类型 1确认 2取消");
    }



}
